

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=&#34;auto&#34;>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/ttntt.gitee.io/img/logo.png">
  <link rel="icon" type="image/png" href="/ttntt.gitee.io/img/logo.png">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="一个不甘做程序员的后端程序员">
  <meta name="author" content="nigntbird">
  <meta name="keywords" content="">
  <title>Java基础 - nigntbird 的个人博客</title>

  <link  rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.staticfile.org/github-markdown-css/4.0.0/github-markdown.min.css" />
  <link  rel="stylesheet" href="/ttntt.gitee.io/lib/hint/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/10.0.0/styles/github-gist.min.css" />
    
  

  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_pf9vaxs7x7b.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/ttntt.gitee.io/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script  src="/ttntt.gitee.io/js/utils.js" ></script>
  <script  src="/ttntt.gitee.io/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.2.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/ttntt.gitee.io/">&nbsp;<strong>nigntbird 的个人博客</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/ttntt.gitee.io/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/ttntt.gitee.io/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/ttntt.gitee.io/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/ttntt.gitee.io/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/ttntt.gitee.io/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;</a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" href="javascript:">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner intro-2" id="background" parallax=true
         style="background: url('/ttntt.gitee.io/img/bg/post_bg.jpg') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="container page-header text-center fade-in-up">
            <span class="h2" id="subtitle">
              
            </span>

            
              <div class="mt-3">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-author" aria-hidden="true"></i>
      nigntbird
    </span>
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2020-10-12 12:38" pubdate>
        2020年10月12日 下午
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      6.1k 字
    </span>
  

  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      阅读了 
      67
       分钟
    </span>
  

  
  
    
      <!-- 不蒜子统计文章PV -->
      <span id="busuanzi_container_page_pv" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="busuanzi_value_page_pv"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid">
  <div class="row">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-md">
      <div class="container nopadding-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto" id="post">
            <!-- SEO header -->
            <h1 style="display: none">Java基础</h1>
            
              <p class="note note-info">
                
                  本文最后更新于：2 个月前
                
              </p>
            
            <div class="markdown-body" id="post-body">
              <h1 id="FAQ"><a href="#FAQ" class="headerlink" title="FAQ"></a>FAQ</h1><h2 id="当在-try-块或-catch-块中遇到-return-语句时，finally-语句块将在⽅法返回之前被执⾏。"><a href="#当在-try-块或-catch-块中遇到-return-语句时，finally-语句块将在⽅法返回之前被执⾏。" class="headerlink" title="当在 try 块或 catch 块中遇到 return 语句时，finally 语句块将在⽅法返回之前被执⾏。"></a>当在 try 块或 catch 块中遇到 return 语句时，finally 语句块将在⽅法返回之前被执⾏。</h2><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">f</span>(<span class="hljs-params"><span class="hljs-keyword">int</span> <span class="hljs-keyword">value</span></span>)</span> &#123;
 <span class="hljs-keyword">try</span> &#123;
 <span class="hljs-keyword">return</span> <span class="hljs-keyword">value</span> * <span class="hljs-keyword">value</span>;
 &#125; <span class="hljs-keyword">finally</span> &#123;
 <span class="hljs-keyword">if</span> (<span class="hljs-keyword">value</span> WX <span class="hljs-number">2</span>) &#123;
 <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
 &#125;
 &#125;
 &#125;<span class="hljs-comment">//调用f(2)将返回0</span></code></pre>
<h2 id="对于不想进⾏序列化的变量，使⽤-transient-关键字修饰。"><a href="#对于不想进⾏序列化的变量，使⽤-transient-关键字修饰。" class="headerlink" title="对于不想进⾏序列化的变量，使⽤ transient 关键字修饰。"></a>对于不想进⾏序列化的变量，使⽤ transient 关键字修饰。</h2><h2 id="JavaEE-企业版-、JavaSE-标准版-、JavaME-微型版"><a href="#JavaEE-企业版-、JavaSE-标准版-、JavaME-微型版" class="headerlink" title="JavaEE(企业版)、JavaSE(标准版)、JavaME(微型版)"></a>JavaEE(企业版)、JavaSE(标准版)、JavaME(微型版)</h2><ul>
<li>JavaEE 号称有十三种核心技术。它们分别是：JDBC、JNDI、EJB、RMI、Servlet、JSP、XML、JMS、Java IDL、JTS、JTA、JavaMail和JAF。</li>
</ul>
<h2 id="Java是半编译型语言"><a href="#Java是半编译型语言" class="headerlink" title="Java是半编译型语言"></a>Java是半编译型语言</h2><p>C是编译型语言(一次性编译成机器码),Python是解释型语言(一句句解释为机码)<br>Java是先编译为字节码,然后再解释字节码为机器码.(因此达到了跨平台的效果).</p>
<blockquote>
<p>.java文件<br>=[JDK中的javac<strong>编译</strong>] =&gt; .class文件(JVM可理解的Java字节,不同平台使用相同的字节码(被不同的虚拟机解释),但最后功能相同)<br>=[JVM加载,解释器<strong>解释</strong>]=&gt; 机器可执行的二进制机器码(JVM加载器先加载字节码文件,然后解释器解释执行,比较慢,引入JIT编译器,编译过后的字节码对应的机器码会被保存下来下次直接用)</p>
</blockquote>
<h2 id="String-s1-new-String-“abc”-这句话创建了几个字符串对象？"><a href="#String-s1-new-String-“abc”-这句话创建了几个字符串对象？" class="headerlink" title="String s1 = new String(“abc”);这句话创建了几个字符串对象？"></a>String s1 = new String(“abc”);这句话创建了几个字符串对象？</h2><blockquote>
<p>1个或2个。如果池中已存在字符串常量“abc”，则只会在堆空间创建一个字符串常量“abc”。如果池中没有字符串常量“abc”，那么它将首先在池中创建，然后在堆空间中创建，因此将创建总共 2 个字符串对象。</p>
</blockquote>
<h2 id="Java泛型实现"><a href="#Java泛型实现" class="headerlink" title="Java泛型实现"></a>Java泛型实现</h2><p>使用类型擦除</p>
<h2 id="为什么重写equal-就必须重写hashcode"><a href="#为什么重写equal-就必须重写hashcode" class="headerlink" title="为什么重写equal()就必须重写hashcode()"></a>为什么重写equal()就必须重写hashcode()</h2><p>因为,两个对象相等的话hashcode一定是相同的.<br>有相同的hashcode但对象不一定相同.</p>
<h2 id="重载-重写"><a href="#重载-重写" class="headerlink" title="重载/重写"></a>重载/重写</h2><p>重写(运行期):子父类中,子类范围必须比父类大,子类抛出异常小于父类<br>重载(编译期):同一个类中,方法名必须相同,其他返回值类型,访问修饰符,参数列表等都可以不同</p>
<h2 id="short-s1-1-s1-s1-1-有错吗-short-s1-1-s1-1-有错吗？前者不正确，后者正确。"><a href="#short-s1-1-s1-s1-1-有错吗-short-s1-1-s1-1-有错吗？前者不正确，后者正确。" class="headerlink" title="short s1 = 1; s1 = s1 + 1; 有错吗?short s1 = 1; s1 += 1 有错吗？前者不正确，后者正确。"></a>short s1 = 1; s1 = s1 + 1; 有错吗?short s1 = 1; s1 += 1 有错吗？前者不正确，后者正确。</h2><p>对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型，因此 s1+1 运算结果也是 int 型，<br>需要强制转换类型才能赋值给 short 型。而 short s1 = 1; s1 += 1;可以正确编译，因为 s1+= 1;相当于 s1 =<br>(short)(s1 + 1);其中有隐含的强制类型转换。</p>
<h2 id="a-equals-b-必须与a-hashCode-b-hashCode-等值。但a-hashCode-b-hashCode-不一定要与a-equals-等值。"><a href="#a-equals-b-必须与a-hashCode-b-hashCode-等值。但a-hashCode-b-hashCode-不一定要与a-equals-等值。" class="headerlink" title="a.equals(b)必须与a.hashCode()==b.hashCode()等值。但a.hashCode()==b.hashCode()不一定要与a.equals()等值。"></a>a.equals(b)必须与a.hashCode()==b.hashCode()等值。但a.hashCode()==b.hashCode()不一定要与a.equals()等值。</h2><h2 id="多态（编译运行不一致）"><a href="#多态（编译运行不一致）" class="headerlink" title="多态（编译运行不一致）"></a>多态（编译运行不一致）</h2><ul>
<li>1、多态成员变量：编译运行看左边<pre><code>   <pre><div class="caption"><span>f</span></div><code class="hljs Fu">         System.out.println(f.num);&#x2F;&#x2F;f是Fu中的值，只能取到父中的值&#96;&#96;&#96;

- 2.多态成员方法：编译看左边，运行看右边
        &#96;&#96;&#96; Fu f1&#x3D;new Zi();
        System.out.println(f1.show());&#x2F;&#x2F;f1的门面类型是Fu,但实际类型是Zi,所以调用的是重写后的方法。&#96;&#96;&#96;
    

## 常量池

* &#96;String xxx&#96; 语句是把xxx放常量池里的.&#x3D;&#x3D;new&#x3D;&#x3D;出来的对象才放堆里的.

* new出来的对象也可以使用&#96;intern()&#96;方法在常量池中创建一份.

**尽量避免多个字符串拼接**，因为这样会重新创建对象。如果需要改变字符串的话，可以使用 StringBuilder或者StringBuffer。

**数值相等问题,注意[-128,127]之间有缓存**
&#96;Byte,Short,Integer,Long,Character,Boolean；&#96;都使用了常量池的技术,在[-128,127]之间的数值,可以直接走缓存.



















***
# Java集合

&lt;img src&#x3D;&quot;&#x2F;ttntt.gitee.io&#x2F;img&#x2F;images&#x2F;java集合.png&quot; height&#x3D;&quot;800&quot; width&#x3D;&quot;800&quot; zoom&#x2F;&gt;

## ArrayList
- 三个构造方法。
- **快查询，慢增删**
使用时能确定容量最好使用带容量的有参构造，或使用ensureCapacity(容量) 来减少扩容次数，提高效率。

### ArrayList 扩容机制
* 无参构造第一次add后数组容量为10,以后每次扩容1.5倍(&#96;int newCapacity &#x3D; oldCapacity + (oldCapacity &gt;&gt; 1)&#96;)

## LinkList
- 两个构造方法
- **快增删，慢查询**


## HashMap 底层
- 四个构造方法(有一个指定“容量大小”和“加载因子”的构造函数)。
* 初始容量为16,每次扩容为原来的**两倍**.
**为什么是两倍?**
因为:为了让内存放下,需要**对hash值取余(%)来缩短hash长度**,**而 &#96;hash%length&#x3D;&#x3D;hash&amp;(length-1)&#96;的前提是 length 是2的n 次⽅**.
这也就进一步解释了计算位置为什么是使用&#96; (n - 1) &amp; hash &#96; .
实现算法:</code></pre></code></pre>
/**<ul>
<li>返回给定容量的两倍</li>
<li>/<br>static final int tableSizeFor(int cap) {<br>int n = cap - 1;<br>n |= n j&gt;k 1;<br>n |= n j&gt;k 2;<br>n |= n j&gt;k 4;<br>n |= n j&gt;k 8;<br>n |= n j&gt;k 16;<br>return (n &lt; 0) ? 1 : (n åã MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY<br>: n + 1;<br>}<pre><code class="hljs markdown"><span class="hljs-section">### jdk1.8前</span>
使用<span class="hljs-strong">**链表散列**</span>(数组+链表)作为存储结构.
<span class="hljs-bullet">*</span> 1.添加元素时,先将key的 hashcode 使用<span class="hljs-strong">**扰动函数**</span>处理
<span class="hljs-bullet">*</span> 2.<span class="hljs-code">` (n - 1) &amp; hash `</span> 判断当前元素的存储位置
<span class="hljs-bullet">    *</span> 没有元素,直接插入
<span class="hljs-bullet">    *</span> 有元素,判断hashcode,及key是否相等,相等则覆盖,否则用<span class="hljs-strong">**拉链法**</span>解决
<span class="hljs-strong">**拉链法:**</span> 将链表和数组相结合。也就是说创建⼀个链表数组，数组中每⼀格就是⼀个链表。若遇到哈希冲突，则将冲突的值加到链表中即可。

<span class="hljs-section">### jdk1.8后</span>
使用<span class="hljs-strong">**链表散列**</span>+<span class="hljs-strong">**红黑树**</span>作为存储结构.
优化1.8:
<span class="hljs-bullet">*</span> <span class="hljs-strong">**扰动函数优化——减少hash冲突**</span>
使用一次扰动代替了1.8以前的4次扰动,
<span class="hljs-strong">**结合了高低位的特征,进一步减少了hash冲突发生的可能.**</span></code></pre>
//jdk1.8扰动函数,结合了高低位的特征,进一步减少了hash冲突发生的可能.<br>static final int hash(Object key) {<br>int h;<br>return (key WX null) ? 0 : (h = key.hashCode()) ^ (h j&gt;k 16);<br>}<pre><code></code></pre>
</li>
</ul>
</li>
</ul>
<ul>
<li>发生冲突<strong>解决</strong>优化<br>当冲突发生后开始依然使用拉链法解决,当拉链到达<strong>阈值8</strong>时,转换为<strong>红黑树</strong>.</li>
</ul>
<h3 id="常见解决hash冲突的方法"><a href="#常见解决hash冲突的方法" class="headerlink" title="常见解决hash冲突的方法"></a>常见解决hash冲突的方法</h3><ul>
<li><p>开放地址法</p>
<p>开放定址法就是一旦发生了冲突，就去寻找下一个空的散列地址，只要散列表足够大，空的散列地址总能找到，并将记录存入。</p>
</li>
<li><p>链地址法</p>
<p>将哈希表的每个单元作为链表的头结点，所有哈希地址为i的元素构成一个同义词链表。即发生冲突时就把该关键字链在以该单元为头结点的链表的尾部。</p>
</li>
<li><p>再哈希法</p>
<p>当哈希地址发生冲突用其他的函数计算另一个哈希函数地址，直到冲突不再产生为止。</p>
</li>
<li><p>建立公共溢出区</p>
<p>将哈希表分为基本表和溢出表两部分，发生冲突的元素都放入溢出表中。</p>
</li>
</ul>
<h2 id="使用HashMap线程不安全怎么办？"><a href="#使用HashMap线程不安全怎么办？" class="headerlink" title="使用HashMap线程不安全怎么办？"></a>使用HashMap线程不安全怎么办？</h2><ul>
<li>ConcurrentHashMap</li>
<li>Collections.SynchronizedMap(与Hashtable性能差不多)<br><code>Map&lt;String, Integer&gt; synchronizedMap = Collections.synchronizedMap(map);</code></li>
<li>Hashtable(弃用)</li>
</ul>
<h2 id="ConcurrentHashMap"><a href="#ConcurrentHashMap" class="headerlink" title="ConcurrentHashMap"></a>ConcurrentHashMap</h2><p><code>Hashtable</code>中采用的锁机制是一次<strong>锁住整个hash表</strong>，从而在同一时刻只能由一个线程对其进行操作；而<strong>ConcurrentHashMap中则是一次锁住一个桶</strong>。</p>
<ul>
<li>jdk1.7</li>
</ul>
<blockquote>
<p>JDK 1.7版本的 <strong>ConcurrentHashMap</strong> 实现线程安全的主要手段，具体一点就是 <strong>Segment + HashEntry + ReentrantLock</strong>。简单来说，<strong>ConcurrentHashMap</strong> 是一个 <strong>Segment</strong> 数组（默认长度为16），每个 <strong>Segment</strong> 又包含了一个 <strong>HashEntry</strong> 数组，所以可以看做一个 <strong>HashMap</strong>， <strong>Segment</strong> 通过继承 <strong>ReentrantLock</strong> 来进行加锁，所以每次需要加锁的操作锁住的是一个 <strong>Segment</strong>，这样只要保证每个 <strong>Segment</strong> 是线程安全的，也就实现了全局的线程安全。</p>
</blockquote>
<ul>
<li>jdk1.8</li>
</ul>
<blockquote>
<p>JDK 1.8 版本摒弃了之前版本中较为臃肿的 <strong>Segment</strong> 分段锁设计，取而代之的是 <strong>Node 数组 + CAS + synchronized + volatile</strong> 的新设计。这样一来，<strong>ConcurrentHashMap</strong> 不仅数据结构变得更简单了（与JDK 1.8 的HashMap类似），锁的粒度也更小了，锁的单位从 <strong>Segment</strong> 变成了 <strong>Node</strong> 数组中的桶（科普：桶就是指数组中某个下标位置上的数据集合，这里可能是链表，也可能是红黑树）。说到红黑树，必须提一下，在JDK 1.8 的 <strong>HashMap</strong> 和 <strong>ConcurrentHashMap</strong> 中，如果某个数组位置上的链表长度过长（大于等于8），就会转化为红黑树以提高查询效率</p>
</blockquote>
<ul>
<li>get()</li>
</ul>
<p>使用 <strong>volatile</strong> 关键字已经足以保证线程在读取数据时不会读取到脏数据，所以没有加锁的必要。</p>
<ul>
<li>put()</li>
</ul>
<ol>
<li>第一次 <strong>put</strong> 元素会初始化 <strong>Node</strong> 数组 (initTable)</li>
<li><strong>put</strong> 操作又分为 <strong>key</strong> (<strong>hash</strong> 碰撞) 存在时的插入和 <strong>key</strong> 不存在时的插入</li>
<li><strong>put</strong> 操作可能会引发数组扩容 (tryPresize) 和链表转红黑树 (treeifyBin)</li>
<li>扩容会使用到数据迁移方法 (transfer)</li>
</ol>
<ul>
<li>CAS</li>
</ul>
<p><strong>CAS</strong> 操作是新版本 <strong>ConcurrentHashMap</strong> 线程安全实现原理的精华所在，如果说其共享变量的读取全靠 <strong>volatile</strong> 实现线程安全的话，那么存储和修改过程除了使用少量的 <strong>synchronized</strong> 关键字外，主要是靠 <strong>CAS</strong> 操作实现线程安全的。</p>
<h2 id="HashSet如何检查重复"><a href="#HashSet如何检查重复" class="headerlink" title="HashSet如何检查重复"></a>HashSet如何检查重复</h2><p>当你把对象加⼊ HashSet 时，HashSet会先计算对象的 hashcode 值来判断对象加⼊的位置，同时也会与其他加⼊的对象的hashcode值作⽐较，如果没有相符的hashcode，HashSet会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,<strong>这时会调⽤ equals() ⽅法来检查hashcode相等的对象是否真的相同。</strong></p>
<h2 id="Arraylist-与-LinkedList-区别"><a href="#Arraylist-与-LinkedList-区别" class="headerlink" title="Arraylist 与 LinkedList 区别?"></a>Arraylist 与 LinkedList 区别?</h2><ul>
<li>1.<ul>
<li>ArrayList 采⽤数组存储,查询快,增删慢,支持随机访问( RandomAccess 接口标识作用)</li>
<li>LinkedList 采⽤链表存储,增删快,查询慢</li>
</ul>
</li>
</ul>
<h2 id="list-的遍历⽅式选择："><a href="#list-的遍历⽅式选择：" class="headerlink" title="list 的遍历⽅式选择："></a>list 的遍历⽅式选择：</h2><ul>
<li>实现了 RandomAccess 接⼝的list，优先选择普通 for 循环 ，其次 foreach,</li>
<li>未实现 RandomAccess 接⼝的list，优先选择iterator遍历（foreach遍历底层也是通过iterator实现的,），⼤size的数据，千万不要使⽤普通for循环</li>
</ul>
<h2 id="comparable-和-Comparator的区别"><a href="#comparable-和-Comparator的区别" class="headerlink" title="comparable 和 Comparator的区别"></a>comparable 和 Comparator的区别</h2><ul>
<li><p>Comparable接口实际上是出⾃java.lang包 它有⼀个 compareTo(Object obj) ⽅法⽤来排序.<br>一般通过继承后重写compareTo方法来排序.</p>
</li>
<li><p>Comparator接⼝实际上是出⾃ java.util 包它有⼀个 compare(Object obj1, Objectobj2) ⽅法⽤来排序.<br>一般通过传入一个Comparator对象在集合排序的第二个参数中来排序.</p>
</li>
</ul>
<hr>
<h1 id="Java中的异常"><a href="#Java中的异常" class="headerlink" title="Java中的异常"></a>Java中的异常</h1><p>都是从Throwable这个基类继承而来，分为了Error和Exception；</p>
<ul>
<li>Error 类是指 java 运行时系统的内部错误和资源耗尽错误；</li>
<li>Exception是所有异常类的父类，又进一步分为<strong>Checked异常(编译时异常)</strong> 和 <strong>UnChecked异常(运行时异常)</strong> ，<br>UnChecked异常 不检查是指的是编译器不会检查异常是否被处理，可以直接<strong>抛出</strong>也可以<strong>处理</strong>，常见的RuntimeException，像ClassNotFound、IllegalArgumentException等都是非检查异常<br><img src="/ttntt.gitee.io/img/images/Java%E5%BC%82%E5%B8%B8.png" srcset="/ttntt.gitee.io/img/loading.gif"></li>
</ul>
<hr>
<h1 id="Java中的流"><a href="#Java中的流" class="headerlink" title="Java中的流"></a>Java中的流</h1><ul>
<li>按照流的方向：输入流（inputStream）和输出流（outputStream）。</li>
<li>按照实现功能分：节点流（可以从或向一个特定的地方（节点）读写数据。如 FileReader）和处理流（是对一个<br>已存在的流的连接和封装，通过所封装的流的功能调用实现数据读写。如 BufferedReader。处理流的构造方法总是要<br>带一个其他的流对象做参数。一个流对象经过其他流的多次包装，称为流的链接。）</li>
<li>按照处理数据的单位：字节流和字符流。字节流继承于 InputStream 和 OutputStream，字符流继承于<br>InputStreamReader 和 OutputStreamWriter</li>
</ul>
<p>** 不管是⽂件读写还是⽹络发送接收，信息的最⼩存储单元都是字节，那为什么 I/O 流操作要分为字节流操作和字符流操作呢？ **</p>
<blockquote>
<p>字符流是由 Java 虚拟机将字节转换得到的，问题就出在这个过程还算是⾮常耗时，并且，如果我们不知道编码类型就很容易出现乱码问题。所以， I/O 流就⼲脆提供了⼀个直接操作字符的接⼝，⽅便我们平时对字符进⾏流操作。</p>
</blockquote>
<h2 id="BIO-NIO-AIO-有什么区别"><a href="#BIO-NIO-AIO-有什么区别" class="headerlink" title="BIO,NIO,AIO 有什么区别?"></a>BIO,NIO,AIO 有什么区别?</h2><ul>
<li>BIO (Blocking I/O): 同步阻塞 I/O 模式，数据的读取写⼊必须阻塞在⼀个线程内等待其完成。在活动连接数不是特别⾼（⼩于单机 1000）的情况下，这种模型是⽐较不错的，可以让每⼀个连接专注于⾃⼰的 I/O 并且编程模型简单，也不⽤过多考虑系统的过载、限流等问题。线程池本身就是⼀个天然的漏⽃，可以缓冲⼀些系统处理不了的连接或请求。但是，当⾯对⼗万甚⾄百万级连接的时候，传统的 BIO 模型是⽆能为⼒的。因此，我们需要⼀种更⾼效的 I/O 处理模型来应对更⾼的并发量。</li>
<li>NIO (Non-blocking/New I/O): NIO 是⼀种同步⾮阻塞的 I/O 模型，在 Java 1.4 中引⼊了NIO 框架，对应 java.nio 包，提供了 Channel , Selector，Buffer 等抽象。NIO 中的 N 可以理解为 Non-blocking，不单纯是 New。它⽀持⾯向缓冲的，基于通道的 I/O 操作⽅法。 NIO提供了与传统 BIO 模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和ServerSocketChannel 两种不同的套接字通道实现,两种通道都⽀持阻塞和⾮阻塞两种模式。阻塞模式使⽤就像传统中的⽀持⼀样，⽐较简单，但是性能和可靠性都不好；⾮阻塞模式正好与之相反。对于低负载、低并发的应⽤程序，可以使⽤同步阻塞 I/O 来提升开发速率和更好的维护性；对于⾼负载、⾼并发的（⽹络）应⽤，应使⽤ NIO 的⾮阻塞模式来开发</li>
<li>AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引⼊了 NIO 的改进版 NIO 2,它是异步⾮阻塞的 IO 模型。异步 IO 是基于事件和回调机制实现的，也就是应⽤操作之后会直接返回，不会堵塞在那⾥，当后台处理完成，操作系统会通知相应的线程进⾏后续的操作。AIO 是异步 IO 的缩写，虽然 NIO 在⽹络操作中，提供了⾮阻塞的⽅法，但是 NIO 的 IO ⾏为还是同步的。对于 NIO 来说，我们的业务线程是在 IO 操作准备好时，得到通知，接着就由这个线程⾃⾏进⾏ IO 操作，IO 操作本身是同步的。查阅⽹上相关资料，我发现就⽬前来说 AIO 的应⽤还不是很⼴泛，Netty 之前也尝试使⽤过 AIO，不过⼜放弃了</li>
</ul>
<hr>
<h1 id="并发"><a href="#并发" class="headerlink" title="并发"></a>并发</h1><h2 id="并发是同一时间段发生-并行是同一时刻发生-进程是资源分配的最小单位，线程是CPU调度的最小单位"><a href="#并发是同一时间段发生-并行是同一时刻发生-进程是资源分配的最小单位，线程是CPU调度的最小单位" class="headerlink" title="并发是同一时间段发生,并行是同一时刻发生,进程是资源分配的最小单位，线程是CPU调度的最小单位"></a>并发是同一时间段发生,并行是同一时刻发生,进程是资源分配的最小单位，线程是CPU调度的最小单位</h2><h2 id="为什么要用多线程"><a href="#为什么要用多线程" class="headerlink" title="为什么要用多线程"></a>为什么要用多线程</h2><p>因为cpu处理速度很快，但是其他的设备很慢，cpu把一堆作业处理完得到了需要的结果后，其他地方却很慢才能把结果传出去，让人很着急，这就出现了阻塞，所以：</p>
<p><u>那些<strong>一定会阻塞的操作</strong>大部分会使用到多线程</u>，磁盘的读取，网络请求的处理，这些操作受制于环境必须阻塞。</p>
<h2 id="线程安全问题"><a href="#线程安全问题" class="headerlink" title="线程安全问题"></a>线程安全问题</h2><h3 id="什么是线程安全："><a href="#什么是线程安全：" class="headerlink" title="什么是线程安全："></a>什么是线程安全：</h3><p>多线程环境下，<strong>多个线程同时访问同一个资源的情况</strong>，由于每个线程执行的过程是不可控的，所以很可能导致最终的结果与实际上的愿望相违背或者直接导致程序出错。比如两个线程同时对一个变量进行操作，每个线程对count变量累加1000次，预期的逻辑是count被累加了2000次，而代码执行的结果却不是2000，所以它是线程不安全的。</p>
<h3 id="线程不安全的原因："><a href="#线程不安全的原因：" class="headerlink" title="线程不安全的原因："></a>线程不安全的原因：</h3><ul>
<li>原子性：一个或者多个操作在 CPU 执行的过程中被中断</li>
<li>可见性：一个线程对共享变量的修改，另外一个线程不能立刻看到</li>
<li>有序性：程序执行的顺序没有按照代码的先后顺序执行</li>
</ul>
<h3 id="线程不安全的解决办法："><a href="#线程不安全的解决办法：" class="headerlink" title="线程不安全的解决办法："></a>线程不安全的解决办法：</h3><p><strong>针对问题1</strong>：JDK里面提供了很多atomic类，比如AtomicInteger, AtomicLong, AtomicBoolean等等，这些类本身可以通过CAS来保证操作的原子性；另外Java也提供了各种锁机制，来保证锁内的代码块在同一时刻只能有一个线程执行，比如刚刚的例子我们就可以加锁，如下：<br><code>java synchronized (Test.class)&#123; count ++; &#125;</code><br>这样，就能够保证一个线程在多count值进行读、改、写操作时，其他线程不可对count进行操作，从而保证了线程的安全性。<br><strong>针对问题2</strong>：同样可以通过synchronized关键字加锁来解决。与此同时，java还提供了一种轻量级的锁，即<code>volatile</code>关键字，要优于synchronized的性能，同样可以保证修改对其他线程的可见性，但记得<strong>不</strong>保证原子性。volatile一般用于对变量的写操作不依赖于当前值的场景中，比如状态标记量等。<br><strong>针对问题3</strong>：可以通过synchronized关键字定义同步代码块或者同步方法保障有序性，另外也可以通过Lock接口保障有序性。</p>
<h2 id="线程数据共享"><a href="#线程数据共享" class="headerlink" title="线程数据共享"></a>线程数据共享</h2><h3 id="线程间数据共享"><a href="#线程间数据共享" class="headerlink" title="线程间数据共享"></a>线程间数据共享</h3><p><strong>JMM解决了可见性和有序性 ，锁解决了原子性。</strong></p>
<h3 id="线程内数据共享——ThreadLocal"><a href="#线程内数据共享——ThreadLocal" class="headerlink" title="线程内数据共享——ThreadLocal"></a>线程内数据共享——ThreadLocal</h3><p>ThreadLocal 的作用是提供线程内的局部变量，这种变量在线程的生命周期内起作用，减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。</p>
<h2 id="Java中的6种线程状态"><a href="#Java中的6种线程状态" class="headerlink" title="Java中的6种线程状态"></a>Java中的6种线程状态</h2><p><img src="/ttntt.gitee.io/img/images/Java%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%81.png" srcset="/ttntt.gitee.io/img/loading.gif"></p>
<p><img src="/ttntt.gitee.io/img/images/Java%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%812.png" srcset="/ttntt.gitee.io/img/loading.gif"></p>
<h2 id="创建线程的三种方式及区别？"><a href="#创建线程的三种方式及区别？" class="headerlink" title="创建线程的三种方式及区别？"></a>创建线程的三种方式及区别？</h2><ul>
<li><p><strong>继承Thread并且重写其run()方法：</strong> 通过继承Thread实现的线程类，多个线程间无法共享线程类的实例变量。（需要创建不同Thread对象，自然不共享）</p>
</li>
<li><p><strong>实现Runnable接口，重写的其 run() 方法：</strong> 此Thread对象才是真正的线程对象，通过实现Runnable接口的线程类，是互相共享资源的。</p>
</li>
<li><p><strong>使用Callable和Future创建线程：</strong> 从继承Thread类和实现Runnable接口可以看出，上述两种方法都不能有返回值，且不能声明抛出异常。而Callable接口则实现了此两点，Callable接口如同Runable接口的升级版，其提供的call()方法将作为线程的执行体，同时允许有返回值。</p>
<h3 id="一些常用方法"><a href="#一些常用方法" class="headerlink" title="一些常用方法"></a>一些常用方法</h3><ul>
<li><p><strong>start()和run()区别</strong></p>
<blockquote>
<p>用 <strong>start()</strong> 来启动线程，实现了真正意义上的启动线程，此时会出现<strong>异步执行</strong>的效果，虚拟机也会去调用**run()**方法。</p>
</blockquote>
<blockquote>
<p>使用<strong>run()**来启动线程，就不是异步执行了，而是</strong>同步执行**，不会达到使用线程的意义。</p>
</blockquote>
<p>调用start方法方可启动线程，而<em>run方法</em>只是thread的一个普通方法调用，还是<em>在主线程里执行</em>。</p>
</li>
<li><p><strong>sleep()和wait()区别</strong></p>
<p><u>java.lang.Thread. <strong>sleep(long mills)</strong> ：</u>让出CPU资源，但是不会释放锁资源;<br><u>java.lang.Object. <strong>wait()/wait(long mills)</strong> ：</u><em>只能在同步代码块中使用</em>,让出CPU资源和锁资源.</p>
<blockquote>
<p><strong>共同点：</strong></p>
<p>都是导致当前线程<strong>先阻塞后就绪</strong>（加了时间会进入超时等待）。</p>
<p>让出cpu后其他线程获得cpu机会相同。</p>
</blockquote>
</li>
<li><p><strong>yield()</strong></p>
<p>一个静态方法，让当前线程让出cpu资源(优先级更高的线程才有机会获得cpu)，<strong>变为可运行状态</strong>。</p>
</li>
<li><p><strong>join()</strong></p>
<p>使调用该方法的线程成为正在运行的线程，则刚才还在运行的线程将<strong>进入阻塞状态</strong>。</p>
</li>
<li><p><strong>notify和notifyAll的区别</strong></p>
<blockquote>
<p>如果线程调用了对象的 wait()方法，那么线程便会处于该对象的等待池中，等待池中的线程不会去竞争该对象的锁。<br>当有线程调用了对象的 notifyAll()方法（唤醒所有 wait 线程）或 notify()方法（只随机唤醒一个 wait 线程），被唤醒的的线程便会进入该对象的锁池中，锁池中的线程会去竞争该对象锁。也就是说，调用了notify后只要一个线程会由等待池进入锁池，而notifyAll会将该对象等待池内的所有线程移动到锁池中，等待锁竞争.</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<h2 id="中断-停止线程的几种方法"><a href="#中断-停止线程的几种方法" class="headerlink" title="中断/停止线程的几种方法"></a>中断/停止线程的几种方法</h2><h2 id="中断线程"><a href="#中断线程" class="headerlink" title="中断线程"></a>中断线程</h2><p><code>thread.interrupt()</code></p>
<p>仅仅是会<strong>设置该线程的中断状态位为true</strong>，如果当前线程阻塞了将会抛出<strong>InterruptedException异常</strong>。<strong>并且在抛出异常后立即将线程的中断标示位清除，即重新设置为false</strong>。抛出异常是为了线程从阻塞状态醒过来，并在结束线程前让程序员有足够的时间来处理中断请求。</p>
<p>以下情况不会抛出异常：</p>
<ul>
<li><strong>synchronized在获锁的过程中的阻塞态是不能被中断的</strong>（可以设置标志位为true，但是不会抛出异常，因此不能从阻塞态中返回）</li>
<li><strong>lock.lock()</strong></li>
</ul>
<h2 id="停止线程"><a href="#停止线程" class="headerlink" title="停止线程"></a>停止线程</h2><p><code>thread.stop()</code></p>
<p><strong>立即中断一个正在运行的线程,</strong></p>
<h2 id="守护进程"><a href="#守护进程" class="headerlink" title="守护进程"></a>守护进程</h2><ul>
<li>守护线程是为其他线程服务的线程；</li>
<li>所有非守护线程都执行完毕后，虚拟机退出；</li>
<li>守护线程不能持有需要关闭的资源（如打开文件等）</li>
</ul>
<h2 id="四种线程池"><a href="#四种线程池" class="headerlink" title="四种线程池"></a>四种线程池</h2><p><code>newCachedThreadPool</code>   无限线程池。<br><code>newFixedThreadPool</code>  固定大小线程池。<br><code>newSingleThreadExecutor</code>  单个线程的线程池。<br><code>newScheduleThreadPool</code>  支持任务调度的线程池。</p>
<p>几个核心参数的作用：</p>
<ul>
<li><code>corePoolSize</code> 线程池<strong>核心线程数</strong>最大值。</li>
<li><code>maximumPoolSize</code> 线程池<strong>最大线程</strong>大小。</li>
<li><code>keepAliveTime</code> 线程池中<strong>非核心线程</strong>空闲的存活时间大小。</li>
<li><code>unit</code>：线程空闲存活时间单位。</li>
<li><code>workQueue</code> 用于<strong>存放任务的阻塞队列。</strong></li>
<li><code>handler</code> 当队列和最大线程池都满了之后的饱和策略，即<strong>拒绝策略</strong>。</li>
<li><code>threadFactory</code>：创建新线程的工厂，所有线程都是通过该工厂创建的，有默认实现。</li>
</ul>
<p>便于理解，附上一张图：</p>
<p><img src="/ttntt.gitee.io/img/images/%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%8F%82%E6%95%B0%E5%8F%AF%E8%A7%86%E5%8C%96.jpg" srcset="/ttntt.gitee.io/img/loading.gif"></p>
<h2 id="线程池5种状态"><a href="#线程池5种状态" class="headerlink" title="线程池5种状态"></a>线程池5种状态</h2><p><img src="/ttntt.gitee.io/img/images/%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%81%E8%BD%AC%E6%8D%A2.png" srcset="/ttntt.gitee.io/img/loading.gif"></p>
<h2 id="提交线程池任务后处理逻辑"><a href="#提交线程池任务后处理逻辑" class="headerlink" title="提交线程池任务后处理逻辑"></a>提交线程池任务后处理逻辑</h2><p><img src="/ttntt.gitee.io/img/images/%E6%8F%90%E4%BA%A4%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%BB%BB%E5%8A%A1.png" srcset="/ttntt.gitee.io/img/loading.gif"></p>
<h2 id="submit，execute区别"><a href="#submit，execute区别" class="headerlink" title="submit，execute区别"></a>submit，execute区别</h2><p>1、submit方法有返回值，execute没有<br>2、submit方法可以是runnable和callable参数，execute只能是runnable</p>
<h2 id="死锁的产生的四个必要条件"><a href="#死锁的产生的四个必要条件" class="headerlink" title="死锁的产生的四个必要条件"></a>死锁的产生的四个<strong>必要条件</strong></h2><ul>
<li>互斥条件<br>进程对所分配到的资源不允许其进程访问</li>
<li>请求和保持条件<br>进程获得一定资源后,请求其他资源时,无论如何,自己已获得的资源保持不变.</li>
<li>不可剥夺条件<br>进程已获得资源后,在未使用完之前,都不可被剥夺</li>
<li>环路等待条件<br>进程死锁后,发生循环等待</li>
</ul>
<p><strong>避免死锁</strong> 只需要破坏其中一个条件即可:</p>
<ul>
<li>1.破坏互斥条件: 这个条件我们没有办法破坏，因为我们⽤锁本来就是想让他们互斥的（临界资源需要互斥访问）。</li>
<li><ol start="2">
<li>破坏请求与保持条件: ⼀次性申请所有的资源。</li>
</ol>
</li>
<li><ol start="3">
<li>破坏不剥夺条件: 占⽤部分资源的线程进⼀步申请其他资源时，如果申请不到，可以主动释放它占有的资源。</li>
</ol>
</li>
<li><ol start="4">
<li>破坏循环等待条件: 靠按序申请资源来预防。按某⼀顺序申请资源，释放资源则反序释放。破坏循环等待条件。</li>
</ol>
</li>
</ul>
<h2 id="锁升级"><a href="#锁升级" class="headerlink" title="锁升级"></a>锁升级</h2><p>synchronized</p>
<h2 id="线程同步"><a href="#线程同步" class="headerlink" title="线程同步"></a>线程同步</h2><h3 id="synchronized-关键字和-volatile-关键字的区别"><a href="#synchronized-关键字和-volatile-关键字的区别" class="headerlink" title="synchronized 关键字和 volatile 关键字的区别?"></a>synchronized 关键字和 volatile 关键字的区别?</h3><ul>
<li>多线程访问volatile关键字不会发⽣阻塞，⽽synchronized关键字可能会发⽣阻塞.</li>
<li>volatile关键字能保证数据的可⻅性,有序性，但不能保证数据的原⼦性;  synchronized关键字两者都能保证.</li>
<li>volatile关键字主要⽤于解决变量在多个线程之间的可⻅性，⽽ synchronized关键字解决的是多个线程之间访问资源的同步性.</li>
</ul>
<h3 id="还可以使用-原子变量-或-Lock类实现同步访问"><a href="#还可以使用-原子变量-或-Lock类实现同步访问" class="headerlink" title="还可以使用 原子变量 或 Lock类实现同步访问"></a>还可以使用 原子变量 或 Lock类实现同步访问</h3><p>AtomicInteger 和 各种 Lock 都可以确保线程安全。AtomicInteger 的效率高是因为它是互斥区非常小，只有一条指令，而 Lock 的互斥区是拿锁到放锁之间的区域，至少三条指令。</p>
<h3 id="AQS"><a href="#AQS" class="headerlink" title="AQS"></a>AQS</h3>
            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/ttntt.gitee.io/categories/%E5%9F%BA%E7%A1%80/">基础</a>
                    
                      <a class="hover-with-bg" href="/ttntt.gitee.io/categories/%E5%9F%BA%E7%A1%80/Java/">Java</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/ttntt.gitee.io/tags/Java/">Java</a>
                    
                      <a class="hover-with-bg" href="/ttntt.gitee.io/tags/%E9%9D%A2%E8%AF%95/">面试</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">本博客所有文章除特别声明外，均采用 <a target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！</p>
              
              
                <div class="post-prevnext row">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/ttntt.gitee.io/2020/10/12/basic/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">设计模式</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/ttntt.gitee.io/2020/10/12/basic/%E6%A1%86%E6%9E%B6/">
                        <span class="hidden-mobile">框架相关</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
              <!-- Comments -->
              <article class="comments" id="comments">
                
                
  <div id="vcomments"></div>
  <script type="text/javascript">
    function loadValine() {
      addScript('https://cdn.staticfile.org/valine/1.4.14/Valine.min.js', function () {
        new Valine({
          el: "#vcomments",
          app_id: "KlkvDALnR8PRdMQXRDN6iqNu-gzGzoHsz",
          app_key: "xec8mdMRTtI5Hy9fBBjHHoyP",
          placeholder: "说点什么吧",
          path: window.location.pathname,
          avatar: "retro",
          meta: ["nick","mail","link"],
          pageSize: "20",
          lang: "zh-CN",
          highlight: false,
          recordIP: false,
          serverURLs: "",
        });
      });
    }
    waitElementVisible('vcomments', loadValine);
  </script>
  <noscript>Please enable JavaScript to view the <a target="_blank" href="https://valine.js.org" rel="nofollow noopener noopener">comments
      powered by Valine.</a></noscript>


              </article>
            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div id="tocbot"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    
  </main>

  
    <a id="scroll-top-button" href="#" role="button">
      <i class="iconfont icon-arrowup" aria-hidden="true"></i>
    </a>
  

  
    <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
  

  

  

  <footer class="mt-5">
  <div class="text-center py-3">
    <div>
      <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a>
      <i class="iconfont icon-love"></i>
      <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener">
        <span>Fluid</span></a>
    </div>
    
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


    

    
  </div>
</footer>

<!-- SCRIPTS -->
<script  src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js" ></script>
<script  src="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/js/bootstrap.min.js" ></script>
<script  src="/ttntt.gitee.io/js/debouncer.js" ></script>
<script  src="/ttntt.gitee.io/js/main.js" ></script>

<!-- Plugins -->


  
    <script  src="/ttntt.gitee.io/js/lazyload.js" ></script>
  



  



  <script defer src="https://cdn.staticfile.org/clipboard.js/2.0.6/clipboard.min.js" ></script>
  <script  src="/ttntt.gitee.io/js/clipboard-use.js" ></script>



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>





  <script  src="https://cdn.staticfile.org/tocbot/4.11.1/tocbot.min.js" ></script>
  <script>
    $(document).ready(function () {
      var boardCtn = $('#board-ctn');
      var boardTop = boardCtn.offset().top;

      tocbot.init({
        tocSelector: '#tocbot',
        contentSelector: '#post-body',
        headingSelector: 'h1,h2,h3,h4,h5,h6',
        linkClass: 'tocbot-link',
        activeLinkClass: 'tocbot-active-link',
        listClass: 'tocbot-list',
        isCollapsedClass: 'tocbot-is-collapsed',
        collapsibleClass: 'tocbot-is-collapsible',
        collapseDepth: 0,
        scrollSmooth: true,
        headingsOffset: -boardTop
      });
      if ($('.toc-list-item').length > 0) {
        $('#toc').css('visibility', 'visible');
      }
    });
  </script>



  <script  src="https://cdn.staticfile.org/typed.js/2.0.11/typed.min.js" ></script>
  <script>
    var typed = new Typed('#subtitle', {
      strings: [
        '  ',
        "Java基础&nbsp;",
      ],
      cursorChar: "_",
      typeSpeed: 70,
      loop: false,
    });
    typed.stop();
    $(document).ready(function () {
      $(".typed-cursor").addClass("h2");
      typed.start();
    });
  </script>



  <script  src="https://cdn.staticfile.org/anchor-js/4.2.2/anchor.min.js" ></script>
  <script>
    anchors.options = {
      placement: "left",
      visible: "hover",
      
      icon: "❡"
      
    };
    var el = "h1,h2,h3,h4,h5,h6".split(",");
    var res = [];
    for (item of el) {
      res.push(".markdown-body > " + item)
    }
    anchors.add(res.join(", "))
  </script>



  <script  src="/ttntt.gitee.io/js/local-search.js" ></script>
  <script>
    var path = "/ttntt.gitee.io/local-search.xml";
    var inputArea = document.querySelector("#local-search-input");
    inputArea.onclick = function () {
      searchFunc(path, 'local-search-input', 'local-search-result');
      this.onclick = null
    }
  </script>



  <script  src="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.css" />

  <script>
    $('#post img:not(.no-zoom img, img[no-zoom]), img[zoom]').each(
      function () {
        var element = document.createElement('a');
        $(element).attr('data-fancybox', 'images');
        $(element).attr('href', $(this).attr('src'));
        $(this).wrap(element);
      }
    );
  </script>







  
  
    <script>
      !function (e, t, a) {
        function r() {
          for (var e = 0; e < s.length; e++) s[e].alpha <= 0 ? (t.body.removeChild(s[e].el), s.splice(e, 1)) : (s[e].y--, s[e].scale += .004, s[e].alpha -= .013, s[e].el.style.cssText = "left:" + s[e].x + "px;top:" + s[e].y + "px;opacity:" + s[e].alpha + ";transform:scale(" + s[e].scale + "," + s[e].scale + ") rotate(45deg);background:" + s[e].color + ";z-index:99999");
          requestAnimationFrame(r)
        }

        function n() {
          var t = "function" == typeof e.onclick && e.onclick;
          e.onclick = function (e) {
            t && t(), o(e)
          }
        }

        function o(e) {
          var a = t.createElement("div");
          a.className = "heart", s.push({
            el: a,
            x: e.clientX - 5,
            y: e.clientY - 5,
            scale: 1,
            alpha: 1,
            color: c()
          }), t.body.appendChild(a)
        }

        function i(e) {
          var a = t.createElement("style");
          a.type = "text/css";
          try {
            a.appendChild(t.createTextNode(e))
          } catch (t) {
            a.styleSheet.cssText = e
          }
          t.getElementsByTagName("head")[0].appendChild(a)
        }

        function c() {
          return "rgb(" + ~~(255 * Math.random()) + "," + ~~(255 * Math.random()) + "," + ~~(255 * Math.random()) + ")"
        }

        var s = [];
        e.requestAnimationFrame = e.requestAnimationFrame || e.webkitRequestAnimationFrame || e.mozRequestAnimationFrame || e.oRequestAnimationFrame || e.msRequestAnimationFrame || function (e) {
          setTimeout(e, 1e3 / 60)
        }, i(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"), n(), r()
      }(window, document);
    </script>
  











  
    <!-- Baidu Analytics -->
    <script defer>
      var _hmt = _hmt || [];
      (function () {
        var hm = document.createElement("script");
        hm.src = "https://hm.baidu.com/hm.js?68846803d2c2c84a8b0f73b87244ddef";
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(hm, s);
      })();
    </script>
  

  

  

  

  

  





</body>
</html>
